#include "DynamicSpriteNode.h"
#include "..\content\ResManager.h"
#include "..\utils\Profiler.h"

namespace ds {

const int DYN_MAX_SPRITES = 512;

DynamicSpriteNode::DynamicSpriteNode(const std::string& name,const std::string& materialName,SpriteColorMode mode,SpriteBlendMode blendMode) 
	: Node(name,materialName,true) , m_ColorMode(mode) , m_BlendMode(blendMode) {
	m_Positions = new Vec2[DYN_MAX_SPRITES];
	m_Offsets = new RECT[DYN_MAX_SPRITES];
	m_Colors = new Color[DYN_MAX_SPRITES];
	m_Rotations = new float[DYN_MAX_SPRITES];
	m_Scales = new Vec2[DYN_MAX_SPRITES];
	m_Centers = new Vec2[DYN_MAX_SPRITES];
	m_Matrix = new Matrix[DYN_MAX_SPRITES];
	m_Counter = 0;
}


DynamicSpriteNode::~DynamicSpriteNode(void) {
	delete m_Matrix;
	delete m_Centers;
	delete m_Scales;
	delete m_Rotations;
	delete m_Colors;
	delete m_Offsets;
	delete m_Positions;
}

//--------------------------------------------------------------
// Internal method to create the sprite batch node
//--------------------------------------------------------------
void DynamicSpriteNode::onCreateDevice() {
	LOGC(logINFO,"DynamicSpriteNode") << getName() << " - onCreateDevice";
	m_Material = gEngine->getResourceManager().getMaterial(m_MaterialHandle);
	IDirect3DDevice9 * pDevice = gEngine->getDevice();    
	HR(D3DXCreateSprite( pDevice, &pSprite ));
}

//--------------------------------------------------------------
// Internal method to delete the batch node and all sprites
//--------------------------------------------------------------
void DynamicSpriteNode::onDestroyDevice() {
	LOGC(logINFO,"DynamicSpriteNode") << "onDestroyDevice";
	SAFE_RELEASE(pSprite);	
}

void DynamicSpriteNode::addSprite(Sprite* sprite) {	
	if ( m_Counter < DYN_MAX_SPRITES ) {
		m_Positions[m_Counter] = sprite->position;
		m_Offsets[m_Counter] = sprite->offset;
		m_Colors[m_Counter] = sprite->color;
		m_Rotations[m_Counter] = sprite->rotation;
		m_Scales[m_Counter] = sprite->scale;
		m_Centers[m_Counter]= Vec2((sprite->offset.right-sprite->offset.left)/2,(sprite->offset.bottom - sprite->offset.top)/2);
		m_Matrix[m_Counter] = Matrix();		
		++m_Counter;
	}
}

//--------------------------------------------------------------
void DynamicSpriteNode::prepareRendering() {
	PR_START(getName().c_str());	
	if ( m_Counter > 0 ) {
		Viewport *vp = gEngine->getViewport();
		Vec2 vpPos = vp->getPosition();	
		Vec2 vCenter( 0.0f, 0.0f );	
		Vec2 *pos = m_Positions;
		Matrix* mat = m_Matrix;
		float* rotation = m_Rotations;
		Vec2* scaling = m_Scales;
		RECT* offset = m_Offsets;		
		for ( int i = 0; i < m_Counter ; ++i) {						
			pos->x = pos->x - vpPos.x;
			pos->y = pos->y - vpPos.y;
			vCenter = Vec2((offset->right-offset->left)*0.5f*scaling->x,(offset->bottom - offset->top)*0.5f*scaling->y);			
			//Vec2 trans = Vec2(pos->x,pos->y);
			D3DXMatrixTransformation2D(mat,NULL,0.0,scaling,&vCenter,*rotation,pos);
			//D3DXMatrixTransformation2D(mat,NULL,0.0,scaling,NULL,*rotation,pos);
			++pos;
			++mat;
			++rotation;
			++scaling;
			++offset;
		}
	}
	PR_END(getName().c_str());
}

//--------------------------------------------------------------
// Internal method called by the rendering system
//--------------------------------------------------------------
void DynamicSpriteNode::draw() {
	PR_START(getName().c_str());
	if ( m_Counter > 0 ) {
		IDirect3DDevice9 * pDevice = gEngine->getDevice();	
		LPDIRECT3DTEXTURE9 tex = m_Material->getTexture(0)->texture;
		Matrix* mat = m_Matrix;
		RECT* offset = m_Offsets;
		Color* color = m_Colors;
		pSprite->Begin(D3DXSPRITE_ALPHABLEND | D3DXSPRITE_DO_NOT_ADDREF_TEXTURE);
		if ( m_ColorMode == SCM_ADD ) {
			pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_ADD );
		}
		else if ( m_ColorMode == SCM_MODULATE ) {
			pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
		}
		else if ( m_ColorMode == SCM_SUBTRACT ) {
			pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SUBTRACT);
		}
		if ( m_BlendMode == SBM_ADDITIVE ) {		
			pDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_ONE);
			pDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ONE);
		}
		else {
			pDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
			pDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
		}
		for ( int i = 0; i < m_Counter; ++i) {				
			pSprite->SetTransform(mat);
			pSprite->Draw(tex,offset,NULL,NULL,*color);
			gEngine->getDrawCounter()->addSprite();
			++mat;
			++offset;
			++color;
		}
		pSprite->End();		
		pDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
		pDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
	}			
	PR_END(getName().c_str());
}

void DynamicSpriteNode::postRendering() {
	m_Counter = 0;
}

}
